<!doctype html>
<html>
<head>
<title>Docker Terminal</title>
<style>
  body {
      background: #fff;
  }
  h1 {
    margin-bottom: 20px;
    font: 20px/1.5 sans-serif;
  }
  .terminal {
    float: left;
    border: #000 solid 5px;
    font-family: "DejaVu Sans Mono", "Liberation Mono", monospace;
    font-size: 11px;
    color: #f0f0f0;
    background: #000;
  }
  .reverse-video {
    color: #000;
    background: #f0f0f0;
  }
  .tabs-navigation {
      margin: 0;
      padding: 0;
      height: 32px; /*--Set height of tabs--*/
      border-bottom: 1px solid #999;
  }
  #tabs {
      border-bottom: 1px solid #999;
      border-left: 1px solid #999;
      width: 100%;
  }
  ul.tabs-menu li {
      margin: 0;
      padding: 0;
      height: 31px; /* Subtract 1px from the height of the unordered list */
      line-height: 31px; /* Vertically aligns the text within the tab */
      border: 1px solid #999;
      border-left: none;
      background: #e0e0e0;
  }
  ul.tabs-menu li a {
      text-decoration: none; /* No link underline */
      color: #000;
      padding: 0 20px;
      border: 1px solid #fff; /* Gives the bevel look with a 1px white border inside the list item */
  }
  ul.tabs-menu li.is-active {
      background: #fff;
      border-bottom: 1px solid #fff; /* Makes the active tab look like it's connected with its content */
  }
  .tab-panel {
      padding: 20px;
  }
</style>
<link rel="stylesheet" type="text/css" href="vendor/react-simpletabs-0.4.21.min.css" />
</head>
<body>

<h1>Docker Terminal</h1>
<p style="color: red">Please note that Docker terminal will <a href="https://github.com/docker/docker/issues/19398">not work</a> with a Docker daemon version 1.9.X, please upgrade or downgrade.</p>
<label>Host: <input id="setting_host" value=""></input></label><br>
<hr>
<div id="tabs"></div>
<div>Your container is <span id="container_id">______</span></div>
<br>
<div id="term_container"></div>

<script src="vendor/react-0.12.2.min.js"></script>
<script src="vendor/JSXTransformer-0.12.2.min.js"></script>
<script src="vendor/react-simpletabs-0.4.21.min.js"></script>
<script src="vendor/term.js"></script>
<script src="vendor/jquery-1.10.1.min.js"></script>
<script>
  window.docker_server = window.location.hostname + ":2375";
  $('#setting_host').val(window.docker_server);
</script>
<script type="text/jsx">
function ApiUrl () {
  return 'http://' + $('#setting_host').val();
}
function imagename (image) {
  var hasrepodigests = image.RepoDigests != null && image.RepoDigests.length > 0 &&
    !(image.RepoDigests.length == 1 && image.RepoDigests[0] === "<none>@<none>");
  var hasrepotags = image.RepoTags != null && image.RepoTags.length > 0 &&
    !(image.RepoTags.length == 1 && image.RepoTags[0] === "<none>:<none>");

  var shortid;
  if (hasrepodigests) {
    var seploc = image.RepoDigests[0].indexOf(':');
    shortid = image.RepoDigests[0].slice(0, seploc+7);
  } else {
    var seploc = image.Id.indexOf(':');
    shortid = image.Id.slice(0, seploc > 0 ? seploc+7 : 6);
  }

  if (hasrepotags) {
    return image.RepoTags[0] + ' (' + shortid + ')';
  } else {
    return shortid;
  }
}
function containername (container) {
  var cid = container.Id.slice(0,6);
  if (container.Names != undefined && container.Names.length > 0) {
    return container.Names[0].replace('/','') + ' (' + cid + ')';
  } else if (container.Name != undefined) {
    // This was obtained with a call to /containers/<ID>/json, note Name vs Names
    return container.Name.replace('/','') + ' (' + cid + ')';
  } else {
    return cid;
  }
}

window.docker = (function() {
  var docker = {};
  docker.terminal = {
    startTerminalForContainer: function(host, container) {
      var term = new Terminal({
        'cols': 150, 'rows': 40,
        'parent': document.getElementById('term_container')
      });
      term.open();

      var wsUri = "ws://" +
        host +
        "/v1.12/containers/" +
        container +
        "/attach/ws?logs=1&stderr=1&stdout=1&stream=1&stdin=1";

      var websocket = new WebSocket(wsUri);
      websocket.onopen = function(evt) { onOpen(evt) };
      websocket.onclose = function(evt) { onClose(evt) };
      websocket.onmessage = function(evt) { onMessage(evt) };
      websocket.onerror = function(evt) { onError(evt) };

      term.on('data', function(data) {
        websocket.send(data);
      });

      function onOpen(evt) {
        term.write("Session started\r\n");
      }

      function onClose(evt) {
        term.write("Session terminated\r\n");
      }

      function onMessage(evt) {
        term.write(evt.data);
      }

      function onError(evt) {
      }
    }
  };

  return docker;
})();

var Tabs = ReactSimpleTabs;
var App = React.createClass({
  getInitialState: function () {
    return {
      'images': [], 'selectedImageId': '',
      'containers': [], 'selectedContainerId': '',
      'tabActive': 1
    };
  },
  render: function() {
    var imageOptions = this.state.images.map(function (image) {
      return <option value={image.Id}>{imagename(image)}</option>;
    }, this);
    var containerOptions = this.state.containers.map(function (container) {
      return <option value={container.Id}>{containername(container) + ' - ' + container.Image}</option>;
    }, this);
    return (
      <Tabs onBeforeChange={this.onTabChange} tabActive={this.state.tabActive}>

        <Tabs.Panel title='Run new image'>
          <button onClick={this.onRefreshImages}>Refresh available images</button><br />
          <label>Available images:
            <select onChange={this.onImageChange} value={this.state.selectedImageId}>
              {imageOptions}
            </select>
          </label><br />
          <button onClick={this.onStartImage}>Start image</button><br />
        </Tabs.Panel>

        <Tabs.Panel title='Attach to container'>
          <button onClick={this.onRefreshContainers}>Refresh available containers</button><br />
          <label>Available containers:
            <select onChange={this.onContainerChange} value={this.state.selectedContainerId}>
              {containerOptions}
            </select>
          </label><br />
          <button onClick={this.onAttachContainer}>Attach to container</button><br />
        </Tabs.Panel>

      </Tabs>
    );
  },
  onTabChange: function (tabActive) {
    this.setState({'tabActive': tabActive});
  },
  onRefreshImages: function () {
    $.get(ApiUrl() + '/v1.12/images/json', function (imagelist) {
      this.setState({'images': imagelist, 'selectedImageId': imagelist.length ? imagelist[0].Id : ''});
    }.bind(this));
  },
  onRefreshContainers: function () {
    $.get(ApiUrl() + '/v1.12/containers/json', function (containerlist) {
      this.setState({'containers': containerlist, 'selectedContainerId': containerlist.length ? containerlist[0].Id : ''});
    }.bind(this));
  },
  onImageChange: function (e) {
    this.setState({'selectedImageId': e.target.value});
  },
  onStartImage: function () {
    $('.terminal').remove();
    $.ajax({
      type: 'POST',
      dataType: "json",
      contentType: "application/json",
      url: ApiUrl() + '/v1.12/containers/create',
      data: JSON.stringify({ "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true,
        "OpenStdin": true, "StdinOnce": true, "Cmd":["/bin/bash"], "Hostname":"test1", "Privileged": false,
        "Image": this.state.selectedImageId }),
      success: function (containerid) {
        containerid = containerid.Id; // there's no other data in this object
        $.ajax({
          type: 'POST',
          dataType: "json",
          contentType: "application/json",
          url: ApiUrl() + '/v1.12/containers/' + containerid + '/start',
          success: function () {
            docker.terminal.startTerminalForContainer($('#setting_host').val(), containerid);
            $.get(ApiUrl() + '/v1.12/containers/' + containerid + '/json', function (container) {
              $('#container_id').text(containername(container));
            });
          }
        });
      }
    });
  },
  onAttachContainer: function () {
    $('.terminal').remove();
    var container;
    this.state.containers.map(function (c) {
      if (c.Id === this.state.selectedContainerId) { container = c; }
    }, this);
    docker.terminal.startTerminalForContainer($('#setting_host').val(), container.Id);
    $('#container_id').text(containername(container));
  }
});
React.renderComponent(<App />, document.getElementById('tabs'));
</script>
</body>
</html>
